
# When UI use single <input type="file" /> to upload image, use picture service

from model.item_picture import ItemPictureDao
from werkzeug.utils import secure_filename
from lib.form import Form
from lib.validator import Validator
from cfg import cfg

from service.file import FileService
from bson.dbref import DBRef
from bson.objectid import ObjectId
import os

class ItemPictureService(FileService):
    def __init__(self, company_name, item_id):
        """Arguments:
            company_name -- string type
            item_id -- BSON ObjectId type
        """
        self.item_id = str(item_id)
        self.company_name = company_name
        
        self.base_path = cfg.picture_base
        self.builtin_path = self.get_default_path() 
        self.dao = ItemPictureDao()
        
    def get_item_pictures(self, query={}):
        """ Get item_picture datas for display
        """
        item_pictures = []
        _item_pictures = self.dao.find(query)
        for _item_picture in _item_pictures:
            item = self.item_dao.find_one({'_id':_item_picture['item_ref'].id})
            item_pictures.append({"fname":_item_picture.fpath, "item-name":item.name})
        return item_pictures


    def submit_item_picture(self, fpath, item_id):
        item_dbref = DBRef('items', item_id)
        picture = self.dao.find_one({'item_ref':item_dbref})
        if picture is None:
            _dict = {'fpath':fpath, 'item_ref': item_dbref}
            return self.dao.save(_dict)
        else:
            picture.fpath = fpath
            return self.dao.save(picture)
        
    def get_folder(self):
        return r'{0}/{1}/{2}'.format(self.base_path, self.company_name, self.item_id)
    
    def get_path(self, fname):
        return r'./{0}/{1}'.format( self.get_folder(), fname)
        
    def get_default_path(self):
        """ Get default picture path for all items within company
        """
        return r'{0}/built_in/default.jpg'.format(self.base_path)#, self.company_name)
        
   

    def get_picture_path(self, fname):
        """
        Arguments:
            fname -- string type
        Return:
            If file name is not None, return full path, otherwise return built in default picture path
        """
        if self.exist(fname, self.get_folder()):
            return self.get_path(fname)
        else:
            return self.get_default_path()
    
           
    def get_pictures(self):
        return os.listdir(r'./{0}'.format( self.get_folder()))
    
        
    def create_picture_folders(self):
        ''' Create a picture folder for item if not exist, the path is ./datas/images/company_name/item_id
        Arguments:
            item --- Item model object
        '''
        # The upload path is relative to the app root
        return self.make_dirs(self.get_folder())
    
    def upload(self, _file):
        '''Upload single file to the server, if file exist overwrite it, otherwise create folders and file.
        Arguments:
        _file -- form.request.files object
        '''
        fname = secure_filename(_file.filename)

        # Check if file is in database already
        folder = self.get_folder()
        fpath = self.get_path(fname)
        if self.exist(fname, folder):
            self.remove_file(fpath)
            _file.save(fpath)
        else:
            if not self.exist(fname, folder):
                self.create_picture_folders()
            _file.save(fpath)

    def update(self, _file, old_fname):
        """Arguments:
            old_fname -- The file name to be replaced, could be None
        """
        if old_fname is not None:
            old_fpath = self.get_path(secure_filename(old_fname))
            self.remove_file( old_fpath )
        self.upload(_file)

    def delete_picture(self, picture, del_record=False):
        '''Delete picture from the disk, use a default picture
        Arguments:
        picture -- The model class of Picture or the dict type
        '''
        ret_picture = None
        if isinstance(picture,dict):
            ret_picture = self.dao.find_one({'_id': picture['_id']})
        else:
            ret_picture = self.dao.find_one({'_id': picture._id})
        
        if ret_picture.fname is not None:            
            fpath = self.get_path(ret_picture.fname)
            self.remove_file(fpath)
        
        if del_record:
            self.dao.remove(ret_picture)
        else:# set a default picture
            ret_picture.fname = None
            self.dao.save(ret_picture)
        #pictures = self.dao.find({'item.$id': self.item._id})
        
        
    def delete_pictures(self):
        """Delete all the pictures under the folder
        """
        _path = r'./' + self.get_folder()
        self.remove_dirs(_path)
        
        #self.dao.delete(item_id = item.id)

    def save_picture(self, picture, mode=None):
        ''' Could be add new picture or update picture
        Arguments:
            picutre --- The Picture model object
            _file --- The file object from the request
            item --- The Item model object
        '''
        # Save file info to database
        if mode is None:
            self.dao.save(picture)

class ItemPictureValidator(Validator):
    def __init__(self):
        Validator.__init__(self)
              
        self.rules = {'fpath': { 
                                'required' : [None, True],
                                'minlength':[None, 1],
                                'maxlength':[None, 512]
                                }
        }

    
class ItemPictureForm(Form):
    """ Submit user form
    """
    def __init__(self):
        """Only accept POST request
        """
        Form.__init__(self)
        self.validator = ItemPictureValidator()
        
        if self.is_submitted():
            # Get raw inputs from the request object
            self.raw_inputs = self.get_raw_inputs()
            self.inputs = self.get_inputs(self.raw_inputs)
            self.errors = self.validator.validate(self.inputs)

    def get_inputs(self, raw_inputs):                
        """ Convert inputs type
        """
        return {'fname': raw_inputs['fname'],
                'item-id':ObjectId(raw_inputs['item-id'])
        }
        
    def has_error(self):
        return self.errors != []    

if __name__ == "__main__":
    pass
